﻿using Grow.Domain.EventBus.Cap.SubscriberDomainEvents;
using Grow.Json;
using Grow.Module.Service;
using Grow.Module.Thread;
using Grow.Utils.Exceptions;

namespace Grow.Domain.EventBus.Cap.DomainEventHandlerInvoker
{
    public class DomainEventHandlerInvoker : IDomainEventHandlerInvoker
    {
        private readonly IServiceContext _serviceContext;
        private readonly IJsonContext _jsonContext;
        private readonly ICancellationTokenContext cancellationTokenContext;
        public DomainEventHandlerInvoker(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
            _jsonContext = _serviceContext.GetRequiredService<IJsonContext>();
            cancellationTokenContext = _serviceContext.GetRequiredService<ICancellationTokenContext>();
        }
        public async Task InvokerAsync(SubscriberDomainEventDto subscriberDomainEventDto, CancellationToken cancellationToken = default)
        {
            Type? eventType = Type.GetType(subscriberDomainEventDto.EventType);
            if (eventType is null)
            {
                throw new GrowCheckException($"{nameof(subscriberDomainEventDto.EventType)} is not null");
            }

            Type? eventHandlerType = Type.GetType(subscriberDomainEventDto.EventHandlerType);
            if (eventHandlerType is null)
            {
                throw new GrowCheckException($"{nameof(eventHandlerType)} is not null");
            }
            object eventHandler = _serviceContext.GetRequiredService(eventHandlerType);

            Task<object?>? eventBody = _jsonContext.DeserializeAsync(subscriberDomainEventDto.EventBody, eventType, cancellationToken);
            if (eventBody is null)
            {
                throw new GrowCheckException($"{nameof(eventBody)} is not null");
            }
            System.Reflection.MethodInfo? method = eventHandlerType.GetMethod("ExecuteAsync", new Type[] {
                eventType,typeof(CancellationToken) });
            Task? task = (Task?)method!.Invoke(eventHandler, new object[] { eventBody, cancellationTokenContext.Token });
            await task!;
        }
    }
}

